#include "compiler.h"
#include "lexer.h"
#include "../散列表_unicode切片_编码/散列表_unicode切片_编码.h"

/******************************************************************************
 *                                   词法分析
 * 输入文件 >> posix文件缓冲 >> 编码转换器 >> 字符扫描器 >> 预处理器 >> 词法分析器
 *****************************************************************************/

/* ******** 内部类型 ******** */ 
typedef struct{
    char *   保留词;  //指向对应 utf8编码 保留词的指针
    单词类型 单词类型; // 单词类型编码
} 保留词预编码;

/* ******** 内部函数 ******** */ 
散列表 *   创建保留词散列表(保留词预编码 * 预编码表指针); // 初始化散列表
单词信息体 检查转换保留词(单词信息体 待检查单词信息体);       // 将混合的 标识符 中的保留词筛选出来

/* ******** 内部变量 ******** */
// 字符扫描
uint32_t 单词计数 = 0;
uint16_t 行内单词计数 = 0;
// 行号和列号遵循常见'文本编辑器'的计数标准，从1开始计数
字符信息体 上一字符信息 = { // 保存上一字符信息，以便于根据换行符更新行列号，以及回退
    .错误=EOF, .字节地址=0, .字节长度=0, .位置.行=1, .位置.列=0, .字符='\0'
};
// 单词扫描
散列表 * 保留词散列表指针 = NULL;
static 保留词预编码 保留词预编码表[] = {
    /* ********************************************************************
     *                             声明
     *********************************************************************/
    {"package",   包},         {"包",      包},
    {"module",    模块},       {"模块",    模块},
    {"namespace", 命名域},     {"命名域",  命名域},
    {"link",      链接},       {"链接",    链接},
    {"import",    导入},       {"导入",    导入},
    {"export",    导出},       {"导出",    导出},
    {"interface", 接口},       {"接口",    接口},
    {"type",      类型},       {"类型",    类型}, // 类型声明
    {"struct",    结构体},     {"结构体",  结构体},
    {"union",     共用体},     {"共用体",  共用体},
    {"enum",      枚举体},     {"枚举体",  枚举体},
    {"var",       变量},       {"变量",    变量},
    {"const",     常量},       {"常量",    常量},
    {"let",       设},         {"设",      设},
    {"val",       值},         {"值",      值},
    {"macro",     宏},         {"宏",      宏},
    {"proc",      过程},       {"过程",    过程}, // 程序块
    {"mthd",      方法},       {"方法",    方法}, // 程序块
    {"func",      函数},       {"函数",    函数},
    {"oper",      算符},       {"算符",    算符},
    // 字面运算符
    {"_",         空标识符},
    {"as",        当作},       {"当作",    当作},
    {"is",        是},         {"是",      是},
    {"sizeof",    求尺寸},     {"的尺寸",  的尺寸},
    {"typeof",    求类型},     {"的类型",  的类型},
    {"mod",       取模号},
    {"and",       逻辑与},     {"与",      逻辑与},   {"且",   逻辑与},
    {"or",        逻辑或},     {"或",      逻辑或},// 字面算符
    {"not",       逻辑非},     {"非",      逻辑非},
    {"xor",       逻辑异或},   {"异或",    逻辑异或},
    /* ********************************************************************
     *                           基本数据类型
     *********************************************************************/
    {"date",      数据型}, // 基本类型
    {"bool",      逻辑型},     {"逻辑型",  逻辑型},
    {"true",      逻辑真},     {"真",      逻辑真},
    {"false",     逻辑假},     {"假",      逻辑假},
    {"uint",      自然型},     {"自然型",  自然型},
    {"uint8",     自然型8},
    {"uint16",    自然型16},
    {"uint32",    自然型32},
    {"uint64",    自然型64},
    {"int",       整型},
    {"int8",      整型8},
    {"int16",     整型16},
    {"int32",     整型32},
    {"int64",     整型64},
    {"float",     浮点},
    {"float32",   浮点32},
    {"float64",   浮点64},
    {"char",      字符},
    {"char8",     字符8},
    {"char16",    字符16},
    {"char32",    字符32},
    {"ascii",     ascii字符},
    {"string",    字符串},
    /* ********************************************************************
     *                             流程控制
     *********************************************************************/
    {"label",     标号},        {"标号",    标号},
    {"defer",     善后},        {"善后",    善后},// 函数调用
    {"call",      调用},
    {"return",    返回},        {"返回",    返回},
    {"goto",      转到}, // 流程控制
    {"break",     中止},
    {"continue",  继续},
    {"branch",    分支},  //分支语句
    {"match",     匹配},        {"匹配",    匹配},
    {"if",        如果},        {"若",      如果},     {"如果",      如果},
    {"then",      则},          {"则",      则},
    {"else",      否则},        {"否则",    否则},
    {"loop",      循环},        {"循环",    循环},//循环语句
    {"for",       对于}, //循环语句
    {"until",     直到},        {"直到",    直到},
    {"while",     当},          {"当",      当},
    /* ********************************************************************
     *                           保留词 介词
     *********************************************************************/
    {"void",      待用保留词}, //待用保留词
    {"null",      待用保留词},
    {"nil",       待用保留词},
    {"let",       待用保留词},
    {"class",     待用保留词}, //OOp常见
    {"impl",      待用保留词},
    {"try",       待用保留词},
    {"catch",     待用保留词},
    {"match",     待用保留词},
    {"switch",    待用保留词},
    {"case",      待用保留词},
    {"default",   待用保留词},
    {"form",      介词},  // 保留介词
    {"to",        介词}, 
    {"in",        介词}, 
    {"on",        介词}, 
    {"at",        介词}, 
    {"by",        介词}, 
    {"with",      介词}, 
    {"of",        介词}, 
    {"like",      介词}, 
    {"any",       待用保留词}, //泛型类型
    {"任意",      待用保留词},
    {"可判等",    待用保留词},
    {"可比",      待用保留词},
    {"new",       待用保留词}, //常见容器方法:
    {"make",      待用保留词}, // 创建、复制、容量、长度
    {"copy",      待用保留词},
    {"cap",       待用保留词},
    {"len",       待用保留词},
    {"append",    待用保留词}, //追加、增删改查
    {"insert",    待用保留词},
    {"delete",    待用保留词},
    {"update",    待用保留词},
    {"select",    待用保留词},
    {"get",       待用保留词}, //常见包装方法，留作谓词
    {"set",       待用保留词},
    {"",          空单词} // 尾部停止标识，供导入使用，禁止删除
};

/** 字符扫描器：从文件中按顺序读取一个字符返回[文件不读完不要修改fin，否则数据丢失]
	返回值：扫描字符体中的'.错误'独立提供错误信息，当其为 EOF 时表示文件结束
	关联全局变量：上一字符、上一字符行号、上一字符列号、待取字符、待取字符行号、待取字符列号
 **/

/* 扫描序列信息：保存上一字符信息，从而支持 回退一个字符，但支持回退一次
 *  +--------+--------+
 *  |上一字符 |当前字符 |
 *  +--------+--------+
 */

//文件回吐一个字符，支持EOF，根据上一字符长度回调文件字节指针，同时更新上一字符行列信息，
void 文件_回吐一个字符(FILE * 输入文件) {
    // 检查上一字符，如果是换行应当回退 字符行号
    fseek(输入文件, -(上一字符信息.字节长度), SEEK_CUR);
    上一字符信息.字节长度 = 0; //只支持回退一次，屏蔽多次回退的可能
    // 调整上一字符信息
    if (上一字符信息.字符 == '\n') { //发生换行回退，重置上一字符为 \0
        上一字符信息.字符 = '\0';
    }
    if (上一字符信息.字节长度 != 0) { //上一字符不是空字符式，才调整列号
        上一字符信息.位置.列 --;
    }
}

//读取一个utf8字符，将其转换为'unicode编码'后与'字节地址'、'行列地址'一同返回
字符信息体 文件_扫描字符(FILE * 输入文件) {
    utf8字符体 utf8字符;
    字符信息体 当前字符;
    // 尝试读取，检查文件是否结束
    utf8字符 = 文件_读取utf8字符(输入文件);
    if (utf8字符.长度 == 0) { // EOF错误检查
        当前字符.错误 = EOF;
        当前字符.字节地址 = 上一字符信息.字节地址 + 上一字符信息.字节长度;
        当前字符.字节长度 = 0;
        当前字符.位置.行 = 上一字符信息.位置.行;
        当前字符.位置.列 = 上一字符信息.位置.列 + 1; // 假定文件结尾有一个0长的EOF字符
        当前字符.字符 = EOF;
        上一字符信息 = 当前字符;
        return 当前字符;
    } else {
        当前字符.错误 = 0;
    }
    // 文件未结束，填充'当前字符'信息
    当前字符.字节地址 = 上一字符信息.字节地址 + 上一字符信息.字节长度;
    当前字符.字节长度 = utf8字符.长度;
    当前字符.字符 = utf8转unicode(utf8字符);
    // 更新行列信息
    if (上一字符信息.字符 == '\n') { // 上一字符是换行，重置为新行起始
        当前字符.位置.行 = 上一字符信息.位置.行 + 1;
        当前字符.位置.列 = 1;
    } else { // 之前没有换行，当前行，列+1
        当前字符.位置.行 = 上一字符信息.位置.行;
        当前字符.位置.列 = 上一字符信息.位置.列 + 1;
    }
    // 当前字符后移一位，上一字符保存当前字符信息
    上一字符信息 = 当前字符;
    // 返回
    return 当前字符;
}

/******************************************************************************
 * 错误处理：报告词法分析错误，并指出错误出现的字符位置
 * 行为：打印诊断信息，包括
 *      《文件名》:《行列位置》:《诊断级别》:《错误提示模板》
 *      《源代码行》
 *      《错误指示》
 *****************************************************************************/
// void 词法分析错误() {
//     FILE * 错误文件 = stderr;
//     // 打印第一行错误提示
    
// }


/******************************************************************************
 * 词法分析器/分词器：返回“输入文件”中的下一个 单词
 * 返回值：结构表，包含：单词总计数、单词行计数、单词符号、字符行列地址、类型号、长度
 * 翻译：token:单词
 *****************************************************************************/
// 词法分析器主接口，返回一个带有类型标记的 单词信息体
单词信息体 文件_扫描单词(FILE * 输入文件) {
    字符信息体 读入字符;
    单词信息体 单词信息;
    // 跳过空白，直到读到第一个非空白 或者 换行
    do { //读入标识符剩下的字符
        // 尝试读取首字符，同时检查文件结束错误
        读入字符 = 文件_扫描字符(输入文件); //读入下一字符
    }while(读入字符.错误!=EOF && (是空白(读入字符.字符) && 读入字符.字符!='\n'));
    // 文件结束检查
    if (读入字符.错误 == EOF) { //文件结束，停止读取跳出循环
        单词信息.错误 = EOF;
        单词信息.计数 = 单词计数 + 1;
        单词信息.行内计数 = ++行内单词计数;
        单词信息.字节地址 = 读入字符.字节地址;
        单词信息.位置.行 = 读入字符.位置.行; 单词信息.位置.列 = 读入字符.位置.列;
        单词信息.类型 = 文件结束;
        单词信息.单词切片.长度 = 0;
        return 单词信息;
    }
    // 文件未结束，正常判断，初始化结构体
    单词计数++;         // 更新单词计数
    行内单词计数++;     // 更新行内单词计数
    单词信息.错误 = 0;  // 没有错误，设为0
    单词信息.计数 = 单词计数;
    单词信息.字节地址 = 读入字符.字节地址;
    单词信息.行内计数 = 行内单词计数;
    单词信息.位置 = 读入字符.位置;
    unicode切片_初始化(&(单词信息.单词切片), 8);
    单词信息.字面值.整数 = 0;
    // 下面只需要填充 类型 字面值 错误 即可
    //标识符，同时识别一些特殊字面值，如 true 和 false
    if (是字母(读入字符.字符)||是汉字(读入字符.字符)||(读入字符.字符=='_')) {
        单词信息.类型 = 标识符;
        do { //读入标识符剩下的字符
            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
            读入字符 = 文件_扫描字符(输入文件); //读入下一字符
        }while((读入字符.错误!=EOF) && (是字母数字(读入字符.字符)||是汉字(读入字符.字符)||(读入字符.字符=='_')));
        文件_回吐一个字符(输入文件);  //最后回吐一个字符
        // 检查是否是保留字/关键字
        单词信息 = 检查转换保留词(单词信息);
        if (单词信息.类型 == 标识符) { 单词信息.字面值.标识符 = 单词信息.单词切片; }
    } //数字，不考虑正负号，默认正数，前缀法只支持小写字母
    else if (是数字(读入字符.字符)) {
        单词信息.类型 = 整数字面量;
        // 字面值转换
        if (读入字符.字符 != '0') {                         //10进制数字
            do {
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读入下一字符
            }while((读入字符.错误!=EOF) && 是10进制数字(读入字符.字符));
            文件_回吐一个字符(输入文件);  //最后回吐一个字符
        } else {                                            // 特殊进制数字，前缀法表示
            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
            读入字符 = 文件_扫描字符(输入文件); // 尝试读取进制字母 h x d o b
            if (是10进制数字(读入字符.字符)) { //一般10进制数字 
                do{ //反复读入10进制字符
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    读入字符 = 文件_扫描字符(输入文件);
                }while((读入字符.错误!=EOF) && 是10进制数字(读入字符.字符));
                文件_回吐一个字符(输入文件); //回吐字符扫描器多读入的一个字符
            } // 0x 0o 0b
            else if (读入字符.字符=='x' || 读入字符.字符=='h') {     //16进制数
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读取进制字母 h x o b
                if (是16进制数字(读入字符.字符)) {
                    do {
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        读入字符 = 文件_扫描字符(输入文件);
                    } while((读入字符.错误!=EOF) && 是16进制数字(读入字符.字符));
                    文件_回吐一个字符(输入文件);
                } else {
                    单词信息.错误 = 数字字面量没有实体数据; // 0x 后无数字错误
                }
            } else if (读入字符.字符 == 'o') {                  //8进制数
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读取进制字母 h x o b
                if ('0'<=读入字符.字符 && 读入字符.字符<='7') {
                    do {
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        读入字符 = 文件_扫描字符(输入文件);
                    } while((读入字符.错误!=EOF) && '0'<=读入字符.字符 && 读入字符.字符<='8');
                    文件_回吐一个字符(输入文件);
                } else {
                    单词信息.错误 = 数字字面量没有实体数据; // 0o 后无数字错误
                }
            } else if (读入字符.字符 == 'b') {                  //2进制数
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读取进制字母 h x o b
                if ('0'<=读入字符.字符 && 读入字符.字符<='1') {
                    do {
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        读入字符 = 文件_扫描字符(输入文件);
                    } while((读入字符.错误!=EOF) && '0'<=读入字符.字符 && 读入字符.字符<='1');
                    文件_回吐一个字符(输入文件);
                } else {
                    单词信息.错误 = 数字字面量没有实体数据; // 0b 后无数字错误
                }
            } else if (读入字符.字符 == 'd') {                  //10进制数
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读取进制字母 h x o b
                if ('0'<=读入字符.字符 && 读入字符.字符<='9') {
                    do {
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        读入字符 = 文件_扫描字符(输入文件);
                    } while((读入字符.错误!=EOF) && '0'<=读入字符.字符 && 读入字符.字符<='9');
                    文件_回吐一个字符(输入文件);
                } else {
                    单词信息.错误 = 数字字面量没有实体数据; // 0b 后无数字错误
                }
            } else if (读入字符.字符 == '.') {                  //10进制数浮点数
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                读入字符 = 文件_扫描字符(输入文件); //读取进制字母 h x o b
                if ('0'<=读入字符.字符 && 读入字符.字符<='9') {
                    do {
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        读入字符 = 文件_扫描字符(输入文件);
                    } while((读入字符.错误!=EOF) && '0'<=读入字符.字符 && 读入字符.字符<='9');
                    文件_回吐一个字符(输入文件);
                } else {
                    单词信息.错误 = 数字字面量没有实体数据; // 0b 后无数字错误
                }
            } else { // 0 后跟其它不明字符，认为数字结束，孤立的0
                文件_回吐一个字符(输入文件); // 回吐多读入的字符
            } 
            // 浮点数字面量识别，待实现
        }
        // 最后单独进行 字面量 >> 字面值 转换
        单词信息.字面值.整数 = unicode切片_转整数(单词信息.单词切片, 0);
    } // 字符 和 字符串 类型
    else if (是左引号(读入字符.字符)) {
        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
         //左单引号：转义字符 ' ‘:U+2018
        if (读入字符.字符=='\'' || 读入字符.字符==0x2018) { 
            单词信息.类型 = 字符字面量;
            // 读入第一个编码字符
            读入字符 = 文件_扫描字符(输入文件);
            if (读入字符.错误==EOF||读入字符.字符=='\n'||读入字符.字符=='\t') {//孤立左引号错误，单词结束
                单词信息.错误 = 字符字面量孤立左单引号;
                文件_回吐一个字符(输入文件);
                return 单词信息;
            } 
            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符); //正常字符，加入第一个字符
            // 直接读入右单引号，空字符错误，单词结束
            if (读入字符.字符 == '\''||读入字符.字符==0x2019) {
                单词信息.错误 = 字符字面量为空;
                return 单词信息;
            }
            else if (读入字符.字符 == '\\') { //转义字符 斜杠 \' \\ \' \" \0 \a \b \f \n \r \t \v
                // 读取被转义字符
                读入字符 = 文件_扫描字符(输入文件);
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                if (读入字符.字符 <= 0x7F) { //传统ascii转义字符
                    switch (读入字符.字符) { // 设置转义字符 >> 转义目标字符
                        case '\'': 读入字符.字符 = '\''; break;
                        case '\"': 读入字符.字符 = '\"'; break;
                        case '\\': 读入字符.字符 = '\\'; break;
                        case '0':  读入字符.字符 = '\0'; break;
                        case 'a':  读入字符.字符 = '\a'; break;
                        case 'b':  读入字符.字符 = '\b'; break;
                        case 'f':  读入字符.字符 = '\f'; break;
                        case 'n':  读入字符.字符 = '\n'; break;
                        case 'r':  读入字符.字符 = '\r'; break;
                        case 't':  读入字符.字符 = '\t'; break;
                        case 'v':  读入字符.字符 = '\v'; break;
                        // case 'x':  break; // 16进制直接编码类型
                        default: 单词信息.错误 = 字符字面量不明转义字符; break;
                    }
                } else { //拓展中文转义 \‘ \’ \“ \”
                    switch (读入字符.字符) {
                        case 0x2018: 读入字符.字符 = 0x2018; break; //左单引号‘:U+2018
                        case 0x2019: 读入字符.字符 = 0x2019; break; //右单引号’:U+2019
                        case 0x201c: 读入字符.字符 = 0x201c; break; //左双引号“:U+201C
                        case 0x201d: 读入字符.字符 = 0x201d; break; //右单引号”:U+201D
                        default: 单词信息.错误 = 字符字面量不明转义字符; break;
                    }
                }
                单词信息.字面值.字符 = 读入字符.字符; // 保存字面值
                // 尝试读入右单引号 ' ’
                读入字符 = 文件_扫描字符(输入文件);
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                if (读入字符.字符=='\'' || 读入字符.字符==0x2019) {   // 正常右引号结束 ' ’:U+2019
                    return 单词信息;
                } else {                                            // 非右单引号错误
                    单词信息.错误 = 字符字面量无右单引号;
                    文件_回吐一个字符(输入文件);
                    return 单词信息;
                }
            } else { // 正常字符编码
                单词信息.字面值.字符 = 读入字符.字符; // 保存字面值
                // 读入右单引号
                读入字符 = 文件_扫描字符(输入文件);
                if (读入字符.字符=='\'' || 读入字符.字符==0x2019) {   // 正常右引号结束 ' ’:U+2019
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else {
                    单词信息.错误 = 字符字面量无右单引号;
                    文件_回吐一个字符(输入文件); 
                    return 单词信息;
                }
            }
        }//左双引号：转义字符串类型 " “
        else if(读入字符.字符=='\"' || 读入字符.字符==0x201c) {
            单词信息.类型 = 字符串字面量;
            unicode切片_初始化(&(单词信息.字面值.字符串), 8); //初始化字符串字面值 切片
            // 循环读入字符，直到右双引号 " ”:U+0x201D
            读入字符 = 文件_扫描字符(输入文件);
            while(!(读入字符.字符=='\"'||读入字符.字符==0x201d)) { //不是右双引号
                // 检查并转义后再加入到切片中，支持空字符串
                //非法字符检查，结束字符串匹配
                if (读入字符.字符==EOF||读入字符.字符=='\n'||读入字符.字符=='\t'){
                    单词信息.错误 = 字符串字面量存在非法字符;
                    // 都是空白字符，不用回退字符
                    break;
                } 
                unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                // 转义字符
                if (读入字符.字符 == '\\') {
                    读入字符 = 文件_扫描字符(输入文件); //读取转义后续待字符
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符); //只追加到 单词
                    if (读入字符.字符 <= 0x7F) { //传统ascii转义字符
                        switch (读入字符.字符) { // 设置转义字符 >> 转义目标字符
                        case '\'': 读入字符.字符 = '\''; break;
                        case '\"': 读入字符.字符 = '\"'; break;
                        case '\\': 读入字符.字符 = '\\'; break;
                        case '0':  读入字符.字符 = '\0'; break;
                        case 'a':  读入字符.字符 = '\a'; break;
                        case 'b':  读入字符.字符 = '\b'; break;
                        case 'f':  读入字符.字符 = '\f'; break;
                        case 'n':  读入字符.字符 = '\n'; break;
                        case 'r':  读入字符.字符 = '\r'; break;
                        case 't':  读入字符.字符 = '\t'; break;
                        case 'v':  读入字符.字符 = '\v'; break;
                        case '\n': 读入字符.字符 = -1; //续行符转义，转换成不会被追加的非法字符EOF
                            break;
                        // case 'x':  break; // 16进制直接编码类型
                        default: 单词信息.错误 = 字符串字面量不明转义字符; break;
                        }
                    } else { //拓展中文转义 \‘ \’ \“ \”
                        switch (读入字符.字符) {
                        case 0x2018: 读入字符.字符 = 0x2018; break; //左单引号‘:U+2018
                        case 0x2019: 读入字符.字符 = 0x2019; break; //右单引号’:U+2019
                        case 0x201c: 读入字符.字符 = 0x201c; break; //左双引号‘:U+201C
                        case 0x201d: 读入字符.字符 = 0x201d; break; //右单引号‘:U+201D
                        default: 单词信息.错误 = 字符串字面量不明转义字符; break;
                        }
                    }
                    // 转义完成后，追加字符到 字面值
                    unicode切片_追加(&(单词信息.字面值.字符串), 读入字符.字符);
                } // 一般字符
                else {
                    unicode切片_追加(&(单词信息.字面值.字符串), 读入字符.字符);
                }
                读入字符 = 文件_扫描字符(输入文件); // 读取下一个前缀字符串
            }
            // 追加 右引号 ”
            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
        }
    }
     //界符
    else { //算符出现频率高的放前面：圆括号()、花括号{}、分号;、
        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
        if (读入字符.字符 <= 0x7F) { // ascii 字符
            switch (读入字符.字符) {
            //边缘界符: () [] {}
            case '(': 单词信息.类型 = 左圆括号; break;
            case ')': 单词信息.类型 = 右圆括号; break;
            case '[': 单词信息.类型 = 左方括号; break;
            case ']': 单词信息.类型 = 右方括号; break;
            case '{': 单词信息.类型 = 左花括号; break;
            case '}': 单词信息.类型 = 右花括号; break;
            //中间界符: , . : ;
            case ',': 单词信息.类型 = 逗号;     break;
            case '.': 单词信息.类型 = 实心句号; break;
            case '?': 单词信息.类型 = 问号;     break;
            case ';': 单词信息.类型 = 分号;     break;
            case '\n':
                单词信息.类型 = 换行;
                行内单词计数 = 0;
                break;
            case ':':                           // :、::、:=   '：':U+FF1A
                单词信息.类型 = 冒号;
                读入字符 = 文件_扫描字符(输入文件);     //判等 == 检查
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符==':' || 读入字符.字符==0xff1a) {     //是 ::
                    单词信息.类型 = 双冒号;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //是 :=
                    单词信息.类型 = 冒等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 :、::、:= 回吐一个字符
                break;
            //比较运算符 == != < <= > >= 位运算符 << <<= >> >>=
            case '=': 单词信息.类型 = 等于号;     // =、==、=>
                读入字符 = 文件_扫描字符(输入文件);     //判等 == 检查
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //是 ==
                    单词信息.类型 = 双等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '>') {     //是 =>
                    单词信息.类型 = 双线右双箭头;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 =、==、=> 回吐一个字符
                break;
            case '!': 单词信息.类型 = 感叹号;   // !、!=
                读入字符 = 文件_扫描字符(输入文件);      //不等于 != 检查
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //没结束，是 !=
                    单词信息.类型 = 感叹等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 !、!= 回吐预读字符
                break;
            case '<': 单词信息.类型 = 小于号;     // <、<|、<=、<=>、<-、<->、<<、<<=
                读入字符 = 文件_扫描字符(输入文件);     //预读检查 <= << <<=
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '-') {     //可能是 <-、<->
                    单词信息.类型 = 单线左单箭头;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    读入字符 = 文件_扫描字符(输入文件); //预读检查 <->
                    if (读入字符.错误 == EOF) {        //文件结束，停止读取跳出循环
                        break;
                    } else if (读入字符.字符 == '>') { //是 <->
                        单词信息.类型 = 单线双向单箭头;
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    } else { 文件_回吐一个字符(输入文件); }
                } else if (读入字符.字符 == '=') {     //可能是 <= <=>
                    单词信息.类型 = 小于等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    读入字符 = 文件_扫描字符(输入文件); //预读检查 <=>
                    if (读入字符.错误 == EOF) {        //文件结束，停止读取跳出循环
                        break;
                    } else if (读入字符.字符 == '>') { //是 <=>
                        单词信息.类型 = 双线双向双箭头;
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    } else { 文件_回吐一个字符(输入文件); }
                } else if (读入字符.字符 == '<') {     //可能是 << <<=
                    单词信息.类型 = 双小于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    读入字符 = 文件_扫描字符(输入文件); //预读检查 <<=
                    if (读入字符.错误 == EOF) {        //文件结束，停止读取跳出循环
                        break;
                    } else if (读入字符.字符 == '=') { //是 <<=
                        单词信息.类型 = 双小于等于;
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    } else { 文件_回吐一个字符(输入文件); }
                } else if (读入字符.字符 == '|') {     //是 <|
                    单词信息.类型 = 小于竖线;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 <、<|、<=、<=>、<-、<->、<<、<<= 回吐一个字符
                break;
            case '>': 单词信息.类型 = 大于号;     // >、>=、>>、>>=
                读入字符 = 文件_扫描字符(输入文件);      //预读检查 >= >> >>=
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //没结束，是 >=
                    单词信息.类型 = 大于等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '>') {     //没结束，是 >>
                    单词信息.类型 = 双大于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    读入字符 = 文件_扫描字符(输入文件); //预读检查 >>=
                    if (读入字符.错误 == EOF) {        //文件结束，停止读取跳出循环
                        break;
                    } else if (读入字符.字符 == '=') { //没结束，是 >>=
                        单词信息.类型 = 双大于等于;
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    } else { 文件_回吐一个字符(输入文件); }
                } else { 文件_回吐一个字符(输入文件); } //不是 >、>=、>>、>>= 回吐一个字符
                break;
            //算术运算符+ - * / % += -= *= /= %= ++ -- 注释 // /*
            case '+': 单词信息.类型 = 加号;       // +、++、+=
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '+') {     //没结束，是 ++
                    单词信息.类型 = 双加号;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //没结束，是 +=
                    单词信息.类型 = 加等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 +、++、+=
                break;
            case '-': 单词信息.类型 = 减号;       // -、--、-=、->
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '-') {     //是 --
                    单词信息.类型 = 双减号;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '>') {     //是 ->
                    单词信息.类型 = 单线右单箭头;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //是 -=
                    单词信息.类型 = 减等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 -、--、-=、->
                break;
            case '*': 单词信息.类型 = 星号;       // *、*=
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //是 *=
                    单词信息.类型 = 星等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 *、*=
                break;
            case '/': 单词信息.类型 = 斜杠;       // /、/=、行注释 //、块注释 /*
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     // /=
                    单词信息.类型 = 斜杠等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '/') {     // 单行注释 //
                    单词信息.类型 = 注释;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    do { //读入标识符剩下的字符，直到换行符或者文件结束
                        读入字符 = 文件_扫描字符(输入文件); //读入下一字符
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    }while(!(读入字符.字符=='\n'||读入字符.错误==EOF));
                    if (读入字符.字符 == '\n') { //换行结束时，回吐换行符
                        单词信息.单词切片.长度--;
                        文件_回吐一个字符(输入文件);
                    }
                } else if (读入字符.字符 == '*') {     //块注释 /*
                    单词信息.类型 = 注释;
                    int 块注释嵌套层数 = 1;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                    do {
                        读入字符 = 文件_扫描字符(输入文件); //读入下一字符
                        unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                        if (读入字符.字符 == '/') {        //嵌套一层检查 /*
                            读入字符 = 文件_扫描字符(输入文件);
                            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                            if (读入字符.字符 == '*'){      //新块注释 /*
                                块注释嵌套层数++;
                            } 
                        }else if (读入字符.字符 == '*') {   //跳出一层检查 */
                            读入字符 = 文件_扫描字符(输入文件);
                            unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                            if (读入字符.字符 == '/'){      //新块注释 /*
                                块注释嵌套层数--;
                            }
                        }
                    }while((读入字符.错误!=EOF) && (块注释嵌套层数>0));
                    // 块嵌套退出错误，例如文件结束但是块注释没有结束
                    if (块注释嵌套层数 != 0) {
                        单词信息.错误 = 块注释未正常结束;
                    }
                } else { 文件_回吐一个字符(输入文件); } //不是 /、/=、//、/* 的任何一种
                break;
            case '%': 单词信息.类型 = 百分号;     // %、%=
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //是 %=
                    单词信息.类型 = 百分等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 % %=
                break;
            //位运算符 & | ~ ^ &= |= ~= ^= 逻辑运算符 && ||
            case '&': 单词信息.类型 = 与号;     // &、&&、&=
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '&') {     //是 &&
                    单词信息.类型 = 双与号;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //是 &=
                    单词信息.类型 = 与等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 & && &=
                break;
            case '|': 单词信息.类型 = 竖线;     // |、||、|=、|>
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '|') {     //是 ||
                    单词信息.类型 = 双竖线;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '>') {     //是 |>
                    单词信息.类型 = 竖线大于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //是 |=
                    单词信息.类型 = 竖线等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 |、||、|=、|>
                break;
            case '~': 单词信息.类型 = 波浪号;     // ~
                break;
            case '^': 单词信息.类型 = 杨抑号;     // ^、^=
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {     //是 ^=
                    单词信息.类型 = 杨抑等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 ^、^=
                break;
            case '\\':                             // 转义类型，未来希望支持LaTex风格转义
                读入字符 = 文件_扫描字符(输入文件);
                if (读入字符.错误 == EOF) {
                    break;
                } else if (读入字符.字符 == '\n') {     //续行符，当作空白忽略
                    单词信息.类型 = 空单词;
                    单词信息.单词切片.长度 = 0;
                } else {                               //不支持的转义类型错误
                    文件_回吐一个字符(输入文件);
                    单词信息.错误 = 不明转义符;
                } 
                break;
            default: // 其它为单词错误
                单词信息.错误 = 无效单词;
                break;
            }
        } else { // 高阶 unicode 字符
            switch (读入字符.字符) { 
            //边缘界符: （）
            case 0xff08: 单词信息.类型 = 左圆括号; break;   //'（':U+FF08
            case 0xff09: 单词信息.类型 = 右圆括号; break;   //'）':U+FF09
            //中间界符: ，。：；、
            case 0xff0c: 单词信息.类型 = 逗号;     break;   //'，':U+FF0C
            case 0x3002: 单词信息.类型 = 空心句号; break;   //'。':U+3002
            case 0xff1f: 单词信息.类型 = 问号;     break;   //'？':U+FF1F
            case 0xff1b: 单词信息.类型 = 分号;     break;   //'；':U+FF1B
            case 0x3001: 单词信息.类型 = 顿号;     break;   //'、':U+3001
            case 0xff1a:                        //：、：：、：='：':U+FF1A
                单词信息.类型 = 冒号; 
                读入字符 = 文件_扫描字符(输入文件);     //判等 == 检查
                if (读入字符.错误 == EOF) {            //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符==':' || 读入字符.字符==0xff1a) {     //是 ：：
                    单词信息.类型 = 双冒号;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else if (读入字符.字符 == '=') {     //是 ：=
                    单词信息.类型 = 冒等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 ：、：：、：= 回吐一个字符
                break;
            //比较运算符 ≠ ≤ ≥
            case 0xff01: 单词信息.类型 = 感叹号;            //'！':U+FF01 '！'、'！='
                读入字符 = 文件_扫描字符(输入文件);     //不等于 != 检查
                if (读入字符.错误 == EOF) {           //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {    //是 !=
                    单词信息.类型 = 感叹等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); } //不是 '！'、'！=' 回吐一个字符
                break;
            case 0x2260: 单词信息.类型 = 不等于号; break;   //'≠':U+2260
            case 0x2264: 单词信息.类型 = 小于等于; break;   //'≤':U+FF1B
            case 0x2265: 单词信息.类型 = 大于等于; break;   //'≥':U+FF1B
            //算术运算符 ·  × ÷ ×= ÷=
            //拉丁文中间点'·':U+00B7、连字点'‧':U+2027、加重号'•':U+2022、点号运算符'∙':U+2219 点运算符'⋅':U+22C5
            case 0x00b7: case 0x2022: case 0x2027: case 0x2219: case 0x22c5:
                单词信息.类型 = 中间点;
                读入字符 = 文件_扫描字符(输入文件);
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          //是 ·=
                    单词信息.类型 = 中间点等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'×'回吐一个字符
                break;
            case 0x00d7: case 0x2a2f: case 0x2a09:        //'×':U+00D7 叉乘运算符'⨯':U+2A2F N元乘运算符'⨉':U+2A09
                单词信息.类型 = 叉乘号; 
                读入字符 = 文件_扫描字符(输入文件);
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          //是 ×=
                    单词信息.类型 = 叉乘等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }      //不是'×'回吐一个字符
                break;
            case 0x00f7: 单词信息.类型 = 除号;              //'÷':U+00F7
                读入字符 = 文件_扫描字符(输入文件);
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          //是 ÷=
                    单词信息.类型 = 除等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'÷'回吐一个字符
                break;
            //逻辑运算符 ∧ ∨ ¬ ￢ ∧= ∨= ¬= ￢=
            case 0x2227: 单词信息.类型 = 逻辑与;             //'∧':U+2227 与
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          // ∧=
                    单词信息.类型 = 逻辑与等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'∧'回吐一个字符
                break;
            case 0x2228: 单词信息.类型 = 逻辑或;             //'∨':U+2228 或
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          // ∧=
                    单词信息.类型 = 逻辑或等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'∨'回吐一个字符
                break;
            case 0x00ac: case 0xffe2:           //'¬':U+00AC '￢':U+FFE2 非标记 全角非标记
                单词信息.类型 = 逻辑非;    
                break;
            case 0x2295: 单词信息.类型 = 逻辑异或;              //'⊕':U+2295 逻辑异或 '⊕='
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          // '⊕='
                    单词信息.类型 = 异或等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'⊕'、'⊕='回吐预读字符
                break;
            case 0x2299: 单词信息.类型 = 同或;              //'⊙': U+2299 同或 '⊙='
                读入字符 = 文件_扫描字符(输入文件);      
                if (读入字符.错误 == EOF) {                 //文件结束，停止读取跳出循环
                    break;
                } else if (读入字符.字符 == '=') {          // '⊙='
                    单词信息.类型 = 同或等于;
                    unicode切片_追加(&(单词信息.单词切片), 读入字符.字符);
                } else { 文件_回吐一个字符(输入文件); }     //不是'⊙'、'⊙='回吐一个字符
                break;
            // 集合运算符/关系运算符: ∩ ∪ ∈∊ ∉ Ø 
            case 0x2229: 单词信息.类型 = 交; break;         //'∩':U+2229
            case 0x222a: 单词信息.类型 = 并; break;         //'∪':U+222A
            case 0x2208: case 0x220a:                     //'∈':U+2208 '∊':U+220A
                单词信息.类型 = 属于;  
                break;
            case 0x2209: 单词信息.类型 = 不属于; break;     //'∉':U+2209
            // 集合运算符：不包含与⊄ ⊈、包含于⊂ ⊆、真包含与⊊ ⫋
            case 0x2205: case 0x00d8:                     // 空集'∅':U+2205 带粗线的拉丁文大写字母Ø:U+00D8
                单词信息.类型 = 空集; break;
            case 0x2284: case 0x2288:                      //'⊄':U+2284 '⊈':U+2288
                单词信息.类型 = 不包含与;
                break;
            case 0x2282: case 0x2286:                      //'⊂':U+2282 '⊆':U+2286
                单词信息.类型 = 包含于;
                break;
            case 0x228a: case 0x2acb:                      //'⊊':U+228A '⫋':U+2ACB
                单词信息.类型 = 真包含于;
                break;
            // 有向箭头 ←:U+2190 →:U+2192 ↔:U+2194 ⇒:U+21D2 ⇔:U+21D4
            case 0x2190: 单词信息.类型 = 单线左单箭头; break;
            case 0x2194: 单词信息.类型 = 单线双向单箭头; break;
            case 0x2192: 单词信息.类型 = 单线右单箭头; break;
            case 0x21D2: 单词信息.类型 = 双线右双箭头; break;
            case 0x21D4: 单词信息.类型 = 双线右双箭头; break;
            default:
                单词信息.错误 = 无效单词;
                break;
            }
        }
    }
    return 单词信息;
}

/******************************************************************************
 * 转换保留词：传入一个“标识符”的单词信息体，
 *            如果是“保留词”则将其类型修改为对应保留词的 编码 后返回
 * 返回值：“单词类型”已被纠正的 单词信息体
 * 关联：一个已被初始化的 “散列表”
 * 翻译：keyword:保留词，而不是保留字
 *****************************************************************************/
单词信息体 检查转换保留词(单词信息体 待检查单词信息体) {
    单词类型 保留词类型 = 0;
    // 检查 初始化保留词表
    if (保留词散列表指针 == NULL) { //初始化空散列表
        // fprintf(stdout, "保留词散列表为空，初始化！\n");
        保留词散列表指针 = 创建保留词散列表(保留词预编码表);
    }
    // 查询转换，能查到就转换
    if ((保留词类型=散列表_查询(保留词散列表指针, 待检查单词信息体.单词切片)) != -1) {
        待检查单词信息体.类型 = 保留词类型;
    }
    // 保留词 型 字面量: true false
    if (待检查单词信息体.类型==逻辑真 || 待检查单词信息体.类型==逻辑假) {
        if (待检查单词信息体.类型==逻辑真) {
            待检查单词信息体.字面值.逻辑值 = true;
        }else {
            待检查单词信息体.字面值.逻辑值 = false;
        }
        待检查单词信息体.类型 = 逻辑值字面量;
    }
    return 待检查单词信息体;
}

// 初始化保留字散列表
散列表 * 创建保留词散列表(保留词预编码 * 预编码表指针) {
    散列表 * 新散列表指针 = 创建散列表(127); // 创建散列表，期望256容量
    // 插入保留单词，逐项插入
    int 保留词编码表索引 = 0;
    保留词预编码 当前编码项 = 保留词预编码表[保留词编码表索引];
    while (当前编码项.保留词[0] != '\0') {
        散列表_插入_原始utf8字符串键(新散列表指针, 当前编码项.保留词, 当前编码项.单词类型);
        // 清空临时切片数据区
        保留词编码表索引 ++;
        当前编码项 = 保留词预编码表[保留词编码表索引];
    }
    return 新散列表指针;
}

// gcc -g -Wall lexer.c ../散列表_unicode切片_编码/散列表_unicode切片_编码.c ../unicode切片/unicode切片.c ../utf8_unicode/utf8_unicode.c && ./a.out
// 保留词表 测试
// int main() {
//     散列表 * 新散列表指针 = 创建保留词散列表(保留词预编码表);
//     // 打印散列表
//     散列表_文件序列化打印(*新散列表指针, stdout);
//     fputc('\n', stdout);
// }
